<?php
namespace juven\libs {
    \defined( '_JEXEC' ) or die( 'Restricted access' );
    
    class Autoloader {
        
        /** @var Autoloader */
        private static $_instance = \NULL;
        
        /** @var string */
        private static $_root = \NULL;
        
        public function autoloader($class_name){
            if (\class_exists($class_name, \FALSE)){ return \TRUE; };
            $className_startsAt = \strrpos($class_name,"\\");
            if ($className_startsAt===\FALSE){ // character \ not found in $class_name
                @\error_log("Autoloader->autoloader(): Error: Invalid ClassName Format($class_name), Namespace separator not found , could not load the needed Class");
                return \FALSE; 
            }
            $className = \substr($class_name, $className_startsAt+1);
            $ns = \substr($class_name, 0, $className_startsAt+1);
            $ns = \str_replace("\\", \DIRECTORY_SEPARATOR, $ns);
            $f = $ns.$className.".php";
            $f = \str_replace("juven", self::$_root, $f);
            if (!\is_readable($f)){
                if (juven::eventsManager()!==\NULL){
                    $dtp = new \stdClass(); 
                    $dtp->fileOfClass = $f;
                    $dtp->className = $class_name;
                    $dtp->errorMessage = "File($f) of Class($class_name) is NOT readable or DOES NOT exists, could not load the needed Class"; 
                    $dtp->returnValue = \FALSE;
                    juven::eventsManager()->publish(self::EVENT_onError_FileOfNeededClassIsNotReadableOrDoesNotExists(), $dtp);
                    return $dtp->returnValue;
                } else { 
                    @\error_log("Autoloader->autoloader(): Error: File($f) of Class($class_name) is NOT readable or DOES NOT exists, could not load the needed Class");
                    return \FALSE; 
                }
            };
            if (juven::eventsManager()!==\NULL){
                    $dtp = new \stdClass(); 
                    $dtp->classToLoad = $f; 
                    juven::eventsManager()->publish(self::EVENT_onBeforeLoadNeededClass(), $dtp);
                    require_once $dtp->classToLoad;
                    return \TRUE;
            } else {        
                require_once $f;
                return \TRUE;
            }
        }

        /**
         * @param string $root 
         * @return juven\libs\Autoloader
         * @throws juven\libs\AutoloaderException
         */
        public static function Init($root){
            if( self::$_instance === \NULL ) { 
                self::$_instance = new self();
                self::$_root = $root;
                if (\spl_autoload_register(array(self::$_instance, 'autoloader'))===\FALSE) {
                    throw new AutoloaderException('Could not register Autoload function handler.');
                }
            }
            return self::$_instance;
        }
 
        protected function __construct(){}

        protected function __clone(){}

        public function __destruct() { \spl_autoload_unregister(array(self::$_instance, 'autoloader')); }
    
        public static function EVENT_onError_FileOfNeededClassIsNotReadableOrDoesNotExists(){ return __CLASS__."\\".__FUNCTION__; }
        public static function EVENT_onBeforeLoadNeededClass(){ return __CLASS__."\\".__FUNCTION__; }
 
    }
    
    class AutoloaderException extends juvenException {
        public function __construct($message='', $code=0, $previous=\NULL) {
            parent::__construct($message, $code, $previous);
            
        }
    } 
}
?>
